#include "VTTPackNode.h"

#include <iostream>
using std::cout;
using std::endl;

UINT32 VTTPackNode::objectCount = 0;

/**
  *	Constructs a new pack node object with the desired width and height. The
  * pack node is positioned at 0/0.
  *
  * @param width width of the desired pack node
  * @param height height of the desired pack node
  */
VTTPackNode::VTTPackNode( UINT32 width, UINT32 height )
{
	objectCount++;
	//cout << "VTTPackNode Constructor called, objectCount: " << objectCount << endl;
	mArea[0] = 0;
	mArea[1] = 0;
	mArea[2] = width;
	mArea[3] = height;

	mChildren[0] = 0;
	mChildren[1] = 0;

	mUsedArea = 0;
}

/**
  *	Copy constructor. Copies the whole pack node tree of which the passed
  * pack node is the root.
  *
  * @param vttPackNode root of the pack node tree that is copied
  */
VTTPackNode::VTTPackNode( const VTTPackNode &vttPackNode )
{
	objectCount++;
	//cout << "VTTPackNode Copy-Constructor called, objectCount: " << objectCount << endl;

	mArea[0] = vttPackNode.mArea[0];
	mArea[1] = vttPackNode.mArea[1];
	mArea[2] = vttPackNode.mArea[2];
	mArea[3] = vttPackNode.mArea[3];

	if (vttPackNode.mChildren[0])
		mChildren[0] = new VTTPackNode( *vttPackNode.mChildren[0] );
	else
		mChildren[0] = 0;

	if (vttPackNode.mChildren[1])
		mChildren[1] = new VTTPackNode( *vttPackNode.mChildren[1] );
	else
		mChildren[1] = 0;

	if (vttPackNode.mUsedArea)
		mUsedArea = new VTTPackNode( *vttPackNode.mUsedArea );
	else
		mUsedArea = 0;
}

/**
  *	Constructs a new pack node object. The exact position parameters have to be provided.
  *
  * @param xMin x-coordinate of the upper left point of the pack node
  * @param yMin y-coordinate of the upper left point of the pack node
  * @param xMaxExclusive x-coordinate of the lower right point of the pack node plus one, equal to x_max + 1
  * @param yMaxExclusive y-coordinate of the lower right point of the pack node plus one, equal to y_max + 1
  */
VTTPackNode::VTTPackNode( UINT32 xMin, UINT32 yMin, UINT32 xMaxExclusive, UINT32 yMaxExclusive )
{
	objectCount++;
	//cout << "VTTPackNode Constructor called, objectCount: " << objectCount << endl;
	mArea[0] = xMin;
	mArea[1] = yMin;
	mArea[2] = xMaxExclusive;
	mArea[3] = yMaxExclusive;

	mChildren[0] = 0;
	mChildren[1] = 0;

	mUsedArea = 0;
}

/**
  *	Destroys the pack node object and all the pack node objects in the tree.
  */
VTTPackNode::~VTTPackNode( void )
{
	objectCount--;
	//cout << "VTTPackNode Destructor called, objectCount: " << objectCount << endl;
	if (mChildren[0]) delete mChildren[0];
	if (mChildren[1]) delete mChildren[1];
	if (mUsedArea) delete mUsedArea;
}

/**
  *	Returns the whole area of the pack node in the order x_min, y_min, x_max + 1, y_max + 1
  *
  * @return whole area of the pack node in the order x_min, y_min, x_max + 1, y_max + 1, array with four elements
  */
const UINT32 *VTTPackNode::GetArea( void ) const
{
	return mArea;
}

/**
  *	Returns the height of the pack node area
  *
  * @return height of the pack node area
  */
UINT32 VTTPackNode::GetHeight( void ) const
{
	return mArea[3] - mArea[1];
}

/**
  *	Returns the width of the pack node area
  *
  * @return width of the pack node area
  */
UINT32 VTTPackNode::GetWidth( void ) const
{
	return mArea[2] - mArea[0];
}

/**
  *	Tries to insert a pack node into the unused area. Returns a const pointer
  * to this pack node if this was successful or 0 if it was not.
  *
  * @param width width of the desired pack node that should be inserted
  * @param height height of the desired pack node that should be inserted
  * @return const pointer to the inserted pack node if the insertion was successful or 0 if it was not
  */
const VTTPackNode *VTTPackNode::Insert( UINT32 width, UINT32 height )
{
	const VTTPackNode *used_area = 0;

	if (0 != mChildren[0])
	{
		used_area = mChildren[0]->Insert( width, height );

		if (0 == used_area)
			return mChildren[1]->Insert( width, height );

		return used_area;
	}

	if (width <= GetWidth() && height <= GetHeight())
	{
		mChildren[0] = new VTTPackNode( mArea[0] + width, mArea[1], mArea[2], mArea[1] + height );
		mChildren[1] = new VTTPackNode( mArea[0], mArea[1] + height, mArea[2], mArea[3] );

		mUsedArea = new VTTPackNode( mArea[0], mArea[1], mArea[0] + width, mArea[1] + height );

		return mUsedArea;
	}

	return 0;
}

/**
  *	Overloading of the =operator. Assigns the provided pack node and its whole
  * tree to the pack node object.
  *
  * @param vttPackNode pack node that should be assigned to the pack node object. The whole tree is assigned.
  */
VTTPackNode &VTTPackNode::operator=( const VTTPackNode &vttPackNode )
{
	if (this == &vttPackNode)
		return *this;

	if (mChildren[0]) delete mChildren[0];
	if (mChildren[1]) delete mChildren[1];
	if (mUsedArea) delete mUsedArea;

	mArea[0] = vttPackNode.mArea[0];
	mArea[1] = vttPackNode.mArea[1];
	mArea[2] = vttPackNode.mArea[2];
	mArea[3] = vttPackNode.mArea[3];

	mChildren[0] = new VTTPackNode( *vttPackNode.mChildren[0] );
	mChildren[1] = new VTTPackNode( *vttPackNode.mChildren[1] );

	mUsedArea = new VTTPackNode( *vttPackNode.mUsedArea );

	return *this;
}